#pragma once
#include "MY_API.hpp"
#include <mutex>
#include <stdio.h>

#define SQL_BUFF 4096

class user_table
{
private:
    MYSQL *_mysql;
    std::mutex _mutex;

public:
    user_table(const std::string &host, const std::string &user_name, const std::string &passwd,
               const std::string &database, const unsigned int port)
    {
        _mysql = Mysql_API::mysql_create(host, user_name, passwd, database, port);
        if (_mysql == NULL)
            log_message(ERROR, "用户数据表初始化失败");
    }
    ~user_table()
    {
        Mysql_API::mysql_destory(_mysql);
        _mysql = NULL;
    }

    // 插入用户信息
    bool insert_user(Json::Value &user)
    {
#define INSERT_SQL "insert into user values(null,'%s', password('%s'), 500, 0, 0)"
        if (user["username"].isNull() || user["password"].isNull())
        {
            log_message(ERROR, "创建用户失败，填写信息有误");
            return false;
        }

        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, INSERT_SQL, user["username"].asCString(),
                user["password"].asCString());
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行创建用户sql语句时失败");
                return false;
            }
        }

        return true;
    }

    // 验证用户登录并获取用户相关信息
    bool login(Json::Value &user)
    {
        //log_message(ERROR, "已调用mysql内部的login函数");
#define LOGIN_SQL "select id, score, total_count, win_count from \
        user where username='%s' and password=password('%s')"
        if (user["username"].isNull() || user["password"].isNull())
        {
            log_message(ERROR, "用户登录失败，填写信息有误");
            return false;
        }

        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, LOGIN_SQL, user["username"].asCString(),
                user["password"].asCString());

        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行用户登录sql语句时失败;");
                return false;
            }

            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                log_message(ERROR, "查询登录信息失败");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            log_message(ERROR, "登录用户信息有误");
            return false;
        }

        MYSQL_ROW row_msg = mysql_fetch_row(res);
        //std::cout << "id:"<< std::stoi(row_msg[0]) << "  score:"<<std::stoi(row_msg[1]) << "  total_count:" << std::stoi(row_msg[2]) << "  win_count:" << std::stoi(row_msg[3]) << std::endl;
        user["id"] = std::stoi(row_msg[0]);
        user["score"] = std::stoi(row_msg[1]);
        user["total_count"] = std::stoi(row_msg[2]);
        user["win_count"] = std::stoi(row_msg[3]);
        //std::cout << "问题不在login函数里" << std::endl;
        return true;
    }

    // 通过名称找到用户，并获取用户信息
    bool select_by_name(const std::string &name, Json::Value &user)
    {
#define ST_BY_NAME_SQL "select id, score, total_count, win_count from \
        user where username='%s'"

        if (name.empty())
        {
            log_message(ERROR, "用户名为空，无法查找用户信息");
            return false;
        }

        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, ST_BY_NAME_SQL, name.c_str());

        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行通过名称查找用户sql语句时失败");
                return false;
            }

            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                log_message(ERROR, "用户信息不存在");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            log_message(ERROR, "查找到的用户信息不唯一");
            return false;
        }

        MYSQL_ROW row_msg = mysql_fetch_row(res);
        user["id"] = std::stoi(row_msg[0]);
        user["score"] = std::stoi(row_msg[1]);
        user["total_count"] = std::stoi(row_msg[2]);
        user["win_count"] = std::stoi(row_msg[3]);
        user["username"] = name;

        return true;
    }

    // 通过id找到用户，并获取用户信息
    bool select_by_id(const int id, Json::Value &user)
    {
#define SELE_BY_ID_SQL "select username, score, total_count, win_count \
        from user where id = %d"

        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, SELE_BY_ID_SQL, id);

        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行通过ID查找用户sql语句时失败");
                return false;
            }

            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                log_message(ERROR, "用户信息不存在");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            log_message(ERROR, "查找到的用户信息不唯一");
            return false;
        }

        MYSQL_ROW row_msg = mysql_fetch_row(res);
        user["id"] = id;
        user["score"] = std::stoi(row_msg[1]);
        user["total_count"] = std::stoi(row_msg[2]);
        user["win_count"] = std::stoi(row_msg[3]);
        user["username"] = row_msg[0];

        return true;
    }


    // 通过id找到用户，并获取用户排名信息
    bool select_rank_by_id(const int id, Json::Value &user)
    {
#define SELE_RANK_BY_ID_SQL "select username, score from user order by score DESC limit 10"

        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, SELE_RANK_BY_ID_SQL, id);

        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行通过ID查找用户sql语句时失败");
                return false;
            }

            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                log_message(ERROR, "用户信息不存在");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        int field_num = mysql_num_fields(res);
        if (row_num != 10 || field_num != 2)
        {
            log_message(ERROR, "查找到的用户信息有误");
            return false;
        }

        for (int i = 1; i <= row_num; i++)
        {
            char rank_name[64] = {0};
            char score_name[64] = {0};
            sprintf(rank_name, "rank_%d", i);
            sprintf(score_name, "score_%d", i);
            MYSQL_ROW table_body = mysql_fetch_row(res);
            user[rank_name] = table_body[0];
            user[score_name] = table_body[1];
        }

        return true;
    }

    // 赢了，场数加1，胜利数目加1，分数增加
    bool win(int id)
    {
#define WIN_SQL "update user set total_count = total_count+1, win_count=win_count+1,\
        score = score + 20 where id = %d"

        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, WIN_SQL, id);
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行用户加分失败");
                return false;
            }
        }

        return true;
    }

    // 输了，场数加1，分数减少，其余不变
    bool lose(int id)
    {
#define LOSE_SQL "update user set total_count = total_count+1, \
        score = score - 20 where id = %d"
        
        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, LOSE_SQL, id);

        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行用户扣分失败");
                return false;
            }
        }

        return true;
    }


    // 插入用户数据信息
    bool insert_user_data(Json::Value &user)
    {
#define INSERT_DATA_SQL "insert into user_data values(%d, %d, %d, %d,'%s',null,null)"
        
        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, INSERT_DATA_SQL, user["fight_uid"].asInt(), user["fight_color"].asInt(),
            user["fight_op_num"].asInt(), user["fight_win"].asInt(), user["fight_data"].asCString());
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行插入用户对战数据时失败");
                return false;
            }
        }

        return true;
    }

    bool select_data_rank_by_id(const int id, Json::Value &user)
    {
#define SELE_DATA_RANK_BY_ID_SQL "select fight_id, fight_color, fight_win, fight_time from user_data where fight_uid = %d"

        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, SELE_DATA_RANK_BY_ID_SQL, id);

        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行通过ID查找用户历史数据语句时失败");
                return false;
            }

            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                log_message(ERROR, "用户历史信息不存在");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        int field_num = mysql_num_fields(res);
        if (field_num != 4)
        {
            log_message(ERROR, "查找到的用户信息有误");
            return false;
        }

        for (int i = 1; i <= row_num; i++)
        {
            char fight_id[64] = {0};
            char fight_color[64] = {0};
            char fight_win[64] = {0};
            char fight_time[64] = {0};

            sprintf(fight_id, "fight_id_%d", i);
            sprintf(fight_color, "fight_color_%d", i);
            sprintf(fight_win, "fight_win_%d", i);
            sprintf(fight_time, "fight_time_%d", i);

            MYSQL_ROW table_body = mysql_fetch_row(res);
            user[fight_id] = table_body[0];
            user[fight_color] = table_body[1];
            user[fight_win] = table_body[2];
            user[fight_time] = table_body[3];
        }

        user["row_num"] = row_num;
        user["fight_uid"] = id;
        return true;
    }


    bool select_data_by_fight_id(const u_int64_t id, Json::Value &user)
    {
#define SELE_DATA_BY_FIGHT_ID_SQL "select fight_data, fight_op_num, fight_color from user_data where fight_id = %d"

        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, SELE_DATA_BY_FIGHT_ID_SQL, id);

        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行通过ID查找用户历史数据语句时失败");
                return false;
            }

            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                log_message(ERROR, "用户历史信息不存在");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        int field_num = mysql_num_fields(res);
        if (row_num != 1 && field_num != 3)
        {
            log_message(ERROR, "查找到的用户信息有误");
            return false;
        }

        MYSQL_ROW table_body = mysql_fetch_row(res);
        user["fight_data"] = table_body[0];
        user["fight_op_num"] = table_body[1];
        user["fight_color"] = table_body[2];
        return true;
    }

    // 插入用户数据信息
    bool delete_user_data(int id)
    {
#define DELETE_DATA_SQL "delete from user_data where fight_id = %d"
        
        char sql_commend[SQL_BUFF] = {0};
        sprintf(sql_commend, DELETE_DATA_SQL, id);

        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行删除用户对战数据时失败");
                return false;
            }
        }

        return true;
    }
    
    void prevent_link_broken()
    {
        #define PREVENT_LINK_BROKEN_SQL "select score from user where id = 1"
        
        char sql_commend[SQL_BUFF] = {0};

        MYSQL_RES *res = NULL;
        sprintf(sql_commend, PREVENT_LINK_BROKEN_SQL);
        {
            std::unique_lock<std::mutex> mutex_ptr(_mutex);
            if (Mysql_API::mysql_exec(_mysql, sql_commend) == false)
            {
                log_message(ERROR, "执行心跳定时器语句失败");
                return;
            }

            res = mysql_store_result(_mysql);
        }

        log_message(NORMAL, "心跳正常");
        return;
    }

};


